/*
*    Author : heiden deng(dengjianquan@beyondcent.com)
*    2017/05/15
*    version 0.0.9
*    通用工具方法实现
*/

#include "htsc_types.h"
#include "htsc_grpc_utils.h"
#include "htsc_grpc_properties_constants.h"
#include "htsc_grpc_properties_tools.h"
#include <src/core/lib/support/string.h>
#include <grpc/support/time.h>
#include<stdio.h>
#include <stdlib.h>
#include<string.h>

#ifdef WIN64
#include<winsock2.h>
#include <direct.h>
#include <Windows.h>
#include <process.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#endif // 


int grpc_getpid() {
#ifdef WIN64
	return (int)GetCurrentProcessId();
#else
	return (int)getpid();
#endif // DEBUG

}

uint64_t htsc_get_timestamp_in_mills() {
	uint64_t ret = 0;
	gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
	ret  = now.tv_sec * 1000 + now.tv_nsec / 1000000;
	return ret;
}


static char g_local_ip[100] = {0};

char *get_local_ip() {
	bool bInitIP = false;
	int len = 0;
#ifdef WIN64
	int nAdapter = 0;
	WSADATA wsaData;
	char name[255];//定义用于存放获得的主机名的变量
	char *ip;//定义IP地址变量
	PHOSTENT hostinfo;

	if (g_local_ip[0] != '\0')
	{
		return g_local_ip;
	}
	//调用MAKEWORD（）获得Winsock版本的正确值，用于加载Winsock库

	if (WSAStartup(MAKEWORD(2, 0), &wsaData) == 0) {
		//现在是加载Winsock库，如果WSAStartup（）函数返回值为0，说明加载成功，程序可以继续
		if (gethostname(name, sizeof(name)) == 0) {
			//如果成功地将本地主机名存放入由name参数指定的缓冲区中
			if ((hostinfo = gethostbyname(name)) != NULL) {
				//这是获取主机名，如果获得主机名成功的话，将返回一个指针，指向hostinfo，hostinfo
				//为PHOSTENT型的变量，下面即将用到这个结构体
				while (hostinfo->h_addr_list[nAdapter]) {
					ip = inet_ntoa(*(struct in_addr *)hostinfo->h_addr_list[nAdapter]);
					//调用inet_ntoa（）函数，将hostinfo结构变量中的h_addr_list转化为标准的点分表示的IP
					//地址（如192.168.0.1）
					if (0 != strncmp(ip, "169.254", strlen("169.254"))) {
						len = strlen(ip);
						snprintf(g_local_ip, len + 1, "%s", ip);
						bInitIP = true;
						break;
					}
					nAdapter++;
				}
				
			}
		}
		WSACleanup(); //卸载Winsock库，并释放所有资源
	}

#else
	int i = 0;
	int sockfd;
	struct ifconf ifconf;
	char buf[512];
	struct ifreq *ifreq;
	char* ip;

	if (g_local_ip[0] != '\0')
	{
		return g_local_ip;
	}

	//初始化ifconf
	ifconf.ifc_len = 512;
	ifconf.ifc_buf = buf;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0)
	{
		return "127.0.0.1";
	}
	ioctl(sockfd, SIOCGIFCONF, &ifconf);    //获取所有接口信息
	close(sockfd);
	//接下来一个一个的获取IP地址
	ifreq = (struct ifreq*)buf;

	for (i = (ifconf.ifc_len / sizeof(struct ifreq)); i>0; i--)
	{
		ip = inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr);
		//排除127.0.0.1，继续下一个
		if (strcmp(ip, "127.0.0.1") == 0)
		{
			ifreq++;
			continue;
		}
		bInitIP = true;
		len = strlen(ip);
		snprintf(g_local_ip, len + 1, "%s", ip);
		break;
	}

#endif
	if (!bInitIP)
	{
		snprintf(g_local_ip, strlen(HTSC_GRPC_LOCAL_HOST) + 1, "%s", HTSC_GRPC_LOCAL_HOST);
	}
	return g_local_ip;
}


static char g_provider_applicationName[HTSC_GRPC_PROPERTY_VALUE_MAX_LEN] = { 0 };
char* htsc_get_provider_AppName() {
	char *ptr = NULL;
	if (g_provider_applicationName[0] != '\0')
	{
		return g_provider_applicationName;
	}
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_COMMON_APP, NULL, g_provider_applicationName)) {
		return g_provider_applicationName;
	}
	return NULL;
}

char* get_service_name(char *method_full_name, char *buf, size_t buf_len) {
	char *p_start = NULL;
	char *p_end = NULL;
	int len = 0;
	p_start = strchr(method_full_name, '/');
	p_end = strrchr(method_full_name, '/');
	if (!p_start || !p_end || p_start == p_end)
	{
		return NULL;
	}
	len = p_end - p_start - 1;
	if (len >= buf_len)
	{
		return NULL;
	}
	memset(buf, 0, buf_len);
	snprintf(buf, len + 1, "%s", p_start + 1);
	return buf;
}

void trim(char *strIn, char *strOut) {

	char *start, *end, *temp;//定义去除空格后字符串的头尾指针和遍历指针
	char *pOut = strOut;
	temp = strIn;

	while (*temp == ' ' || *temp == '\t') {
		++temp;
	}

	start = temp; //求得头指针

	temp = strIn + strlen(strIn) - 1; //得到原字符串最后一个字符的指针(不是'\0')

	while (*temp == ' ' || *temp == '\n' || *temp == '\r' || *temp == '\t') {
		--temp;
	}

	end = temp; //求得尾指针


	for (temp = start; temp <= end; ) {
		*pOut++ = *temp++;
	}

	*pOut = '\0';
}


#ifndef WIN64
int get_executable_path(char* processdir, int len, char* processname) {
	char* filename;

	if (readlink("/proc/self/exe", processdir, len) <= 0)
	{
		return -1;
	}	

	filename = strrchr(processdir, PATH_SEPRATOR);//函数查找字符在指定字符串中最后一次出现的位置如果成功，则返回指定字符最后一次出现位置的地址，如果失败，则返回 false  
	if (filename == NULL)
		return -1;
	++filename;
	strcpy(processname, filename);
	*filename = '\0';
	return (int)(filename - processdir);
}
#endif


//#if __STDC_VERSION__ >= 199901L
char* gprc_strdup(const char *str) {
	if (!str)
	{
		return NULL;
	}
	int n = strlen(str) + 1;
	char *dup = malloc(n);
	if (dup) strcpy(dup, str);
	return dup;
}
//#endif

void htsc_log(char *msg) {
	printf("%s\n", msg);
}

int countchar(char *str, char a) {
	int n = 0;
	int i = 0;
	while (*(str + i) != '\0') {
		if (*(str + i) == a)
			n++;
		i++;
	}
	return n;
}


bool isStartWith(const char *pattern, const char* value) {
	if (!pattern || !value)
	{
		return false;
	}
	char *p = (char*)pattern;
	char *q = (char*)value;
	while (p && q)
	{
		if (*p != *q)
		{
			return false;
		}
		p++;
		q++;
	}
	if (!q)
	{
		return true;
	}
	return false;
}

bool isEndsWith(const char *pattern, const char* value) {
	if (!pattern || !value)
	{
		return false;
	}
	char *p = (char*)pattern;
	p = p + strlen(pattern) - 1;

	char *q = (char*)value;
	q = q + strlen(value) - 1;
	while (p != pattern && q != value)
	{
		if (*p != *q)
		{
			return false;
		}
		p--;
		q--;
	}
	if (q == value)
	{
		if (*p == *q) {
			return true;
		}
	}
	return false;
}

/*
拷贝字符串，不包括pEnd位置字符
必须确保buf空间足够大
*/
int copystr0(char* buf, char *pSrc, char *pEnd) {
	size_t len = pEnd - pSrc;
	char *ret = NULL;
	char *p = pSrc;
	char *q = buf;
	if (!pSrc) {
		return -1;
	}
	if (!pEnd) {
		len = strlen(pSrc);
	}
	if (len > 0) {
		while (p != pEnd && *p) {
			*q++ = *p++;
		}
		*q = '\0';
	}
	return 0;

}

char *copystr(char *pSrc, char *pEnd) {
	size_t len = pEnd - pSrc;
	char *ret = NULL;
	char *p = pSrc;
	char *q = NULL;
	if (!pSrc) {
		return ret;
	}
	if (!pEnd) {
		len = strlen(pSrc);
	}
	if (len > 0) {
		ret = (char*)malloc(sizeof(char) * len + 1);
		q = ret;
		while (q && p != pEnd && *p) {
			*q++ = *p++;
		}
		*q = '\0';
	}
	return ret;

}


//将负载均衡枚举类型转成字符串类型,返回空间无需释放
char* lb_strategy_to_str(loadbalance_strategy_t strategy) {
	switch (strategy)
	{
	case GRPCLB:
		return HTSC_GRPC_LB_TYPE_GRPCLB;
		break;
	case PICK_FIRST:
		return HTSC_GRPC_LB_TYPE_PF;
		break;
	case ROUND_ROBIN:
		return HTSC_GRPC_LB_TYPE_RR;
		break;
	case WEIGHT_ROUND_ROBIN:
		return HTSC_GRPC_LB_TYPE_WRR;
		break;
	default:
		return HTSC_GRPC_LB_TYPE_RR;
		break;
	}
}

//将负载均衡字符串类型转成枚举类型
loadbalance_strategy_t lb_strategy_from_str(char *strategy) {
	loadbalance_strategy_t ret = ROUND_ROBIN;
	if (strategy == NULL)
	{
		return ret;
	}
	if (0 == gpr_stricmp(HTSC_GRPC_LB_TYPE_GRPCLB,strategy))
	{
		ret = GRPCLB;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_LB_TYPE_PF, strategy))
	{
		ret = PICK_FIRST;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_LB_TYPE_RR, strategy))
	{
		ret = ROUND_ROBIN;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_LB_TYPE_WRR, strategy))
	{
		ret = WEIGHT_ROUND_ROBIN;
	}
	else {
		ret = ROUND_ROBIN;
	}
	return ret;
}

//将故障切换枚举类型转成字符串类型，范湖空间无需释放
char* cluster_strategy_to_str(cluster_strategy_t strategy) {
	switch (strategy)
	{
	case FAILOVER:
			return HTSC_GRPC_CLUSTER_TYPE_FO;
		break;
	case FAILFAST:
		return HTSC_GRPC_CLUSTER_TYPE_FF;
		break;
	case FAILBACK:
		return HTSC_GRPC_CLUSTER_TYPE_FB;
		break;
	case FORKING:
		return HTSC_GRPC_CLUSTER_TYPE_FK;
		break;
	default:
		return HTSC_GRPC_CLUSTER_TYPE_FO;
		break;
	}
}

//将故障切换字符串类型转成枚举类型
cluster_strategy_t cluster_strategy_from_str(char *strategy) {
	cluster_strategy_t ret = FAILOVER;
	if (strategy == NULL)
	{
		return ret;
	}
	if (0 == gpr_stricmp(HTSC_GRPC_CLUSTER_TYPE_FO, strategy))
	{
		ret = FAILOVER;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_CLUSTER_TYPE_FF, strategy))
	{
		ret = FAILFAST;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_CLUSTER_TYPE_FB, strategy))
	{
		ret = FAILBACK;
	}
	else if (0 == gpr_stricmp(HTSC_GRPC_CLUSTER_TYPE_FK, strategy))
	{
		ret = FORKING;
	}
	else {
		ret = FAILOVER;
	}
	return ret;
}

provider_t* new_provider() {
	provider_t* provider = (provider_t*)malloc(sizeof(provider_t));
	memset(provider, 0, sizeof(provider_t));
	REINIT(provider->protocol);
	snprintf(provider->protocol, sizeof("grpc") + 1, "%s", "grpc");
	provider->username = NULL;
	provider->password = NULL;
	REINIT(provider->host);
	snprintf(provider->host, sizeof("127.0.0.1") + 1,"%s","127.0.0.1");
	provider->port = 0;
	provider->version = NULL;
	provider->group = NULL;
	provider->default_timeout = 1000;
	provider->default_reties = 2;
	provider->default_connections = 0;
	provider->default_requests = 0;
	provider->access_protected = false;
	provider->default_loadbalance = ROUND_ROBIN;
	provider->default_async = false;
	provider->token = NULL;
	provider->deprecated = false;
	provider->dynamic = true;
	provider->accesslog = false;
	provider->owner = NULL;
	provider->weight = 100;
	provider->default_cluster = FAILOVER;
	provider->application = NULL;
	provider->application_version = NULL;
	provider->organization = NULL;
	provider->environment = NULL;
	provider->module = NULL;
	provider->module_version = NULL;
	provider->anyhost = false;
	provider->sInterface = NULL;
	provider->methods = NULL;
	provider->pid = 0;
	snprintf(provider->side, sizeof("provider") + 1, "%s", "provider");
	provider->timestamp = 0;
	provider->grpc = NULL;
	provider->dubbo = NULL;
	provider->flag = 0;
	provider->ext_data = NULL;

	return provider;
}


void init_provider(provider_t *provider) {
	char buf[HTSC_GRPC_PROPERTY_VALUE_MAX_LEN] = {0};
	if (!provider)
	{
		return;
	}
	htsc_grpc_properties_init();
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_COMMON_APP,NULL,buf))
	{
		provider->application = gprc_strdup(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_VERSION, NULL, buf))
	{
		provider->version = gprc_strdup(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_MODULE, NULL, buf))
	{
		provider->module = gprc_strdup(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_GROUP, NULL, buf))
	{
		provider->group = gprc_strdup(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_TIMEOUT, NULL, buf))
	{
		provider->default_timeout = atoi(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_RETIES, NULL, buf))
	{
		provider->default_reties = atoi(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_CONN, NULL, buf))
	{
		provider->default_connections = atoi(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_REQ, NULL, buf))
	{
		provider->default_requests = atoi(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_LB, NULL, buf))
	{
		provider->default_loadbalance = lb_strategy_from_str(buf);
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_ASYNC, NULL, buf))
	{
		provider->default_async = (gpr_stricmp(buf,"true") == 0)?true:false;
	}
	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_TOKEN, NULL, buf))
	{
		provider->token = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEPRECATED, NULL, buf))
	{
		provider->deprecated = (gpr_stricmp(buf, "true") == 0) ? true : false;
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DYNAMIC, NULL, buf))
	{
		provider->dynamic = (gpr_stricmp(buf, "true") == 0) ? true : false;
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_ACCESSLOG, NULL, buf))
	{
		provider->accesslog = (gpr_stricmp(buf, "true") == 0) ? true : false;
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_OWNER, NULL, buf))
	{
		provider->owner = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_WEIGHT, NULL, buf))
	{
		provider->weight = atoi(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DEFAULT_CLUSTER, NULL, buf))
	{
		provider->default_cluster = cluster_strategy_from_str(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_APP_VERSION, NULL, buf))
	{
		provider->application_version = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_ORG, NULL, buf))
	{
		provider->organization = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_ENV, NULL, buf))
	{
		provider->environment = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_MOD_VER, NULL, buf))
	{
		provider->module_version = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_ANYHOST, NULL, buf))
	{
		provider->anyhost = (gpr_stricmp(buf, "true") == 0) ? true : false;
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_DUBBO, NULL, buf))
	{
		provider->dubbo = gprc_strdup(buf);
	}

	REINIT(buf);
	if (0 == htsc_grpc_properties_get_value(HTSC_GRPC_PROPERTIES_P_ACCESS_PROTECTED, NULL, buf))
	{
		provider->access_protected = (gpr_stricmp(buf, "true") == 0) ? true : false;
	}
	
}

void free_provider_v2(provider_t *provider) {
	if (!provider)
	{
		return;
	}
	FREE_PTR(provider->version);
	FREE_PTR(provider->group);
	FREE_PTR(provider->token);
	FREE_PTR(provider->owner);
	FREE_PTR(provider->application);
	FREE_PTR(provider->application_version);
	FREE_PTR(provider->organization);
	FREE_PTR(provider->environment);
	FREE_PTR(provider->module);
	FREE_PTR(provider->module_version);
	FREE_PTR(provider->sInterface);
	FREE_PTR(provider->methods);
	FREE_PTR(provider->grpc);
	FREE_PTR(provider->dubbo);
}

void free_provider(provider_t **p) {
	provider_t *provider = *p;
	if (!provider)
	{
		return;
	}
	free_provider_v2(provider);
	FREE_PTR(provider);
}

/*
* 使用线程Sleep指定毫秒数。
*/
void htsc_grpc_sleep_mills(int64_t millsecond) {
	gpr_timespec span;
	span.tv_sec = millsecond / 1000;
	span.tv_nsec = (millsecond % 1000) * 1000000;
	span.clock_type = GPR_TIMESPAN;
 
	uint64_t ret = 0;
	gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
	gpr_timespec fur = gpr_time_add(now, span);
	gpr_sleep_until(fur);
}